﻿using PlayerRoles.Voice;
using System;
using System.Collections.Generic;
using System.Linq;
using VoiceChat;
using Exiled.API.Features;
using Exiled.API.Features.Pools;
using PlayerRoles.Spectating;
using InventorySystem.Items.Usables.Scp1576;
using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.Scp3114;

namespace CustomCharacter.VoiceChat
{
    public sealed class CustomChannel
    {
        public CustomChannel(string id, string name, string hex, bool coverPrimary)
        {
            Id = id;
            Name = name;
            ColorHex = hex;
            PrimaryCovery = coverPrimary;
            Listener = new List<Player>();
            Sender = new List<Player>();
        }
        public string Id { get; }
        public string Name { get; }
        public string ColorHex { get; }
        public bool PrimaryCovery { get; }
        public List<Player> Listener { get; set; }
        public List<Player> Sender { get; set; }
    }

    public static class VoiceChatManager
    {
        public static void Init()
        {
            Exiled.Events.Handlers.Player.Left.Subscribe((ev) => { ev.Player.VC_ClearListener(); ev.Player.VC_ClearSender(); ev.Player.VC_ResetPrimaryChannel(); });
        }
        //自定义频道
        public static List<CustomChannel> CustomChannels = new List<CustomChannel>();
        //频道接收，包含的玩家会以其他方式收到这些频道信息
        public static Dictionary<VoiceChatChannel, List<Player>> ChannelListener = new Dictionary<VoiceChatChannel, List<Player>>
        {
            { VoiceChatChannel.ScpChat, new List<Player>() { } },
            { VoiceChatChannel.Radio, new List<Player>() { } },
            { VoiceChatChannel.Spectator, new List<Player>() { } }
        };
        //频道发送（可多播），bool值为是否进行ValidateSend
        public static Dictionary<Player, Dictionary<VoiceChatChannel, bool>> ChannelSender = new Dictionary<Player, Dictionary<VoiceChatChannel, bool>>();
        public static Dictionary<Player, VoiceChatChannel> PrimaryChannelModifier = new Dictionary<Player, VoiceChatChannel>();

        public static void VC_CreateChannel(CustomChannel channel)
        {
            if (CustomChannels.Contains(channel))
                return;
            CustomChannels.Add(channel);
        }
        /// <summary>
        /// 添加侦听器
        /// </summary>
        /// <param name="channel">频道，该频道发出的语音一定会发送到该玩家</param>
        public static void VC_AddListener(this Player player, VoiceChatChannel channel)
        {
            if (ChannelListener.ContainsKey(channel))
            {
                ChannelListener[channel].Add(player);
            }
        }
        /// <summary>
        /// 添加侦听器
        /// </summary>
        /// <param name="customChannelId">自定义频道ID，该频道发出的语音一定会发送到该玩家</param>
        public static void VC_AddListener(this Player player, string customChannelId)
        {
            var cc = CustomChannels.FirstOrDefault(x => x.Id == customChannelId);
            if (cc == null)
                return;
            player.VC_AddListener(cc);
        }
        public static void VC_AddListener(this Player player, CustomChannel cc)
        {
            if (cc.Listener.Contains(player))
                return;
            cc.Listener.Add(player);
        }
        public static void VC_ClearListener(this Player player)
        {
            foreach(var list in ChannelListener.Values)
            {
                list.Remove(player);
            }
            foreach (var cc in CustomChannels)
            {
                cc.Listener.Remove(player);
            }
        }
        public static void VC_RemoveListener(this Player player, VoiceChatChannel channel)
        {
            if (ChannelListener.ContainsKey(channel))
            {
                ChannelListener[channel].Remove(player);
            }
        }
        public static void VC_RemoveListener(this Player player, string customChannelId)
        {
            var cc = CustomChannels.FirstOrDefault(x => x.Id == customChannelId);
            if (cc == null)
                return;
            cc.Listener.Remove(player);
        }
        public static void VC_RemoveListener(this Player player, CustomChannel cc)
        {
            cc.Listener.Remove(player);
        }

        /// <summary>
        /// 添加发送器，玩家语音时，会抄送到指定的其他频道中
        /// </summary>
        /// <param name="channel">指定频道，如果与玩家主频道相同则无效</param>
        /// <param name="validateSend">是否验证发送</param>
        public static void VC_AddSender(this Player player, VoiceChatChannel channel, bool validateSend)
        {
            if (!ChannelSender.TryGetValue(player, out var dict))
            {
                dict = DictionaryPool<VoiceChatChannel, bool>.Pool.Get();
                ChannelSender.Add(player, dict);
            }
            if (!dict.ContainsKey(channel))
                dict.Add(channel, validateSend);
            dict[channel] = validateSend;
        }
        public static void VC_AddSender(this Player player, string customChannelId)
        {
            var cc = CustomChannels.FirstOrDefault(x => x.Id == customChannelId);
            if (cc == null)
                return;
            player.VC_AddSender(cc);
        }
        public static void VC_AddSender(this Player player, CustomChannel cc)
        {
            if (cc.Sender.Contains(player))
                return;
            cc.Sender.Add(player);
        }
        public static void VC_RemoveSender(this Player player, VoiceChatChannel channel)
        {
            if (ChannelSender.TryGetValue(player, out var dict))
            {
                if (dict.ContainsKey(channel))
                {
                    dict.Remove(channel);
                    if (dict.Count == 0)
                    {
                        DictionaryPool<VoiceChatChannel, bool>.Pool.Return(dict);
                        ChannelSender.Remove(player);
                    }
                }
            }
        }
        public static void VC_RemoveSender(this Player player, string customChannelId)
        {
            var cc = CustomChannels.FirstOrDefault(x => x.Id == customChannelId);
            if (cc == null)
                return;
            player.VC_RemoveSender(cc);
        }
        public static void VC_RemoveSender(this Player player, CustomChannel cc)
        {
            if (cc.Sender.Contains(player))
                cc.Sender.Remove(player);
        }
        public static void VC_ClearSender(this Player player)
        {
            if (ChannelSender.TryGetValue(player, out var dict))
            {
                DictionaryPool<VoiceChatChannel, bool>.Pool.Return(dict);
                ChannelSender.Remove(player);
            }
            foreach (var cc in CustomChannels)
            {
                cc.Sender.Remove(player);
            }
        }
        /// <summary>
        /// 设定主语音频道，这将改变按下Q时的语音发送，同时禁用ValidateSend
        /// </summary>
        /// <param name="channel">指定频道</param>
        public static void VC_SetPrimaryChannel(this Player player, VoiceChatChannel channel)
        {
            if (!PrimaryChannelModifier.ContainsKey(player))
            {
                PrimaryChannelModifier.Add(player, channel);
            }
            else
              PrimaryChannelModifier[player] = channel;
        }
        public static void VC_ResetPrimaryChannel(this Player player) => PrimaryChannelModifier.Remove(player);
        public static VoiceChatChannel[] VC_GetListener(this Player player)
        {
            List<VoiceChatChannel> list = ListPool<VoiceChatChannel>.Pool.Get();
            foreach(var channel in ChannelListener)
            {
                if (channel.Value.Contains(player))
                    list.Add(channel.Key);
            }
            return ListPool<VoiceChatChannel>.Pool.ToArrayReturn(list);
        }
        public static CustomChannel[] VC_GetCustomListener(this Player player)
        {
            return CustomChannels.Where(x => x.Listener.Contains(player)).ToArray();
        }
        public static VoiceChatChannel[] VC_GetSender(this Player player)
        {
            if (ChannelSender.TryGetValue(player, out var dict))
            {
                return dict.Keys.ToArray();
            }
            return Array.Empty<VoiceChatChannel>();
        }
        public static CustomChannel[] VC_GetCustomSender(this Player player)
        {
            return CustomChannels.Where(x => x.Sender.Contains(player)).ToArray();
        }
        public static VoiceChatChannel GetDefaultCorrectChannel(this Player player)
        {
            if (player.VoiceModule is HumanVoiceModule)
            {
                if (player.IsTransmitting)
                    return VoiceChatChannel.Radio;
                if (Scp1576Item.ValidatedReceivers.Contains(player.ReferenceHub))
                    return VoiceChatChannel.Scp1576;
                return VoiceChatChannel.Proximity;
            }
            if (player.VoiceModule is GlobalVoiceModuleBase g)
            {
                if (g is Scp3114VoiceModule s)
                {
                    if (s.IsSpeaking)
                        return player.VoiceChannel;
                }
                return g.PrimaryChannel;
            }
            return VoiceChatChannel.None;
        }
        public static VoiceChatChannel GetFriendlyChannel(this VoiceModuleBase module, VoiceChatChannel channel) //被ValidateReceive限制? nononono
        {
            if (module is HumanVoiceModule)
            {
                switch (channel)
                {
                    case VoiceChatChannel.ScpChat:
                    case VoiceChatChannel.Spectator:
                        return VoiceChatChannel.RoundSummary;
                }
            }
            else if (module is SpectatorVoiceModule && !(module is LobbyVoiceModule) && !(module is OverwatchVoiceModule))
            {
                switch (channel)
                {
                    case VoiceChatChannel.ScpChat:
                        return VoiceChatChannel.RoundSummary;
                }
            }
            else if (module is StandardScpVoiceModule)
            {
                switch (channel)
                {
                    case VoiceChatChannel.Spectator:
                    case VoiceChatChannel.Scp1576:
                        return VoiceChatChannel.RoundSummary;

                }
            }
            return channel;
        }
    }
}
